home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / Folder Watching / Folder Watcher FBA ƒ / Sources / FBALists.c < prev    next >
Encoding:
Text File  |  1996-02-16  |  8.8 KB  |  372 lines  |  [TEXT/CWIE]

  1. // FBALists.c
  2. //
  3. // Folder Watcher FBA by Greg Sutton
  4. // ©Apple Computer Inc 1996, all rights reserved.
  5.  
  6.  
  7. #include "FBALists.h"
  8.  
  9. #include "FBA.h"
  10. #include "FBATask.h"
  11.  
  12. #include <Memory.h>
  13. #include <Resources.h>
  14. #include <TextUtils.h>
  15. #include <ToolUtils.h>
  16.  
  17.     // Borrowed from MoreFiles 1.3.1
  18. #define hasCatSearch(volParms)        (((volParms).vMAttrib & (1L << bHasCatSearch)) != 0)
  19.  
  20.     // Prototypes
  21. static void                AddToList( ItemPtr* theHeadPtr, ItemPtr theItem );
  22. static void                FirstToLast( ItemPtr* theHeadPtr );
  23. static WatchVolumePtr    VolumeInList( short theVolRef );
  24. static OSErr            GetFullPath( FSSpec* theSpec, StringPtr thePath );
  25. static void                InsertAtBeginning( StringPtr sourceStr, StringPtr destStr );
  26. static OSErr            GetVolInfo( short theVolRef, GetVolParmsInfoBuffer* theBuffer );
  27.  
  28.     // Globals
  29. long                    gNumberFolders = 0;
  30. long                    gNumberVolumes = 0;
  31. WatchFolderPtr            gWatchFolderPtr = NULL;
  32. WatchVolumePtr            gWatchVolumePtr = NULL;
  33.  
  34. // Paths to the folder to be watched are stored in 'WFol' resources. This routine simply
  35. // reads through all of these resources adding them to the list of folders to watch.
  36.  
  37. Boolean    InitWatchFolders( void )
  38. {
  39.     short        count;
  40.     Handle        aHandle;
  41.     FSSpec        aSpec;
  42.     OSErr        err;
  43.     Boolean        result = true;
  44.  
  45.     count = Count1Resources( kWatchFolderResource );
  46.     
  47.     for ( ; count > 0; count-- )
  48.     {                            // Handle to a pascal string
  49.         aHandle = Get1IndResource( kWatchFolderResource, count );
  50.         
  51.         if (! aHandle)
  52.         {
  53.             result = false;        // If we fail on one we'll still try the rest
  54.             continue;
  55.         }
  56.         
  57.         HLock( aHandle );
  58.         err = FSMakeFSSpec( 0, 0, (StringPtr) *aHandle, &aSpec );
  59.         HUnlock( aHandle );
  60.         
  61.         if (noErr != err || ! AddFolder( &aSpec ))
  62.         {
  63.             RmveResource( aHandle );    // Error in finding the folder or
  64.             result = false;                // no longer a file - get rid of it.
  65.         }
  66.         else
  67.             ReleaseResource( aHandle );
  68.     }
  69.     
  70.     return result;
  71. }
  72.  
  73.  
  74. // Check that the FSSpec is for a folder. If it is then create a WatchFolderPtr
  75. // that gets added to the front of the linked list.
  76.  
  77. Boolean    AddFolder( FSSpec* theSpec )
  78. {
  79.     WatchFolderPtr    tempPtr;
  80.     CInfoPBRec        pb;
  81.     OSErr            err;
  82.         
  83.     if ( FolderInList( theSpec ) )
  84.         return true;
  85.  
  86.     err = GetDirInfo( theSpec, &pb );
  87.         // Check there's no error and FSSpec is a directory
  88.     if ( noErr != err || ! ( pb.dirInfo.ioFlAttrib & ioDirMask ) )
  89.         return false;
  90.                                             // If folder is on a different
  91.     if ( ! AddVolume( theSpec->vRefNum ) )    // volume to the others increment.
  92.         return false;                        // Returns false if volume can't
  93.                                             // handle PBCatSearch().
  94.             
  95.     tempPtr = (WatchFolderPtr) NewPtr( sizeof( WatchFolderRec ) );
  96.     tempPtr->theSpec = *theSpec;
  97.     tempPtr->theDirID = pb.dirInfo.ioDrDirID;
  98.     tempPtr->theFileCount = pb.dirInfo.ioDrNmFls;
  99.     tempPtr->next = NULL;
  100.     
  101.     AddToList( (ItemPtr *)&gWatchFolderPtr, (ItemPtr)tempPtr );
  102.  
  103.     gNumberFolders++;
  104.     
  105.     return true;
  106. }
  107.  
  108.  
  109. // Check that the volume supports PBCatSearch(), if so create a
  110. // WatchVolumePtr and add to volume linked list.
  111.  
  112.  
  113. Boolean    AddVolume( short theVolRef )
  114. {
  115.     WatchVolumePtr            tempPtr;
  116.     GetVolParmsInfoBuffer    aBuffer;
  117.     OSErr                    err;
  118.         
  119.     if ( VolumeInList( theVolRef ) )
  120.         return true;
  121.  
  122.     err = GetVolInfo( theVolRef, &aBuffer );
  123.         // Check there's no error and FSSpec is a directory
  124.     if ( noErr != err || ! hasCatSearch( aBuffer ) )
  125.         return false;
  126.             
  127.     tempPtr = (WatchVolumePtr) NewPtr( sizeof( WatchVolumeRec ) );
  128.     tempPtr->theVolRef = theVolRef;
  129.     GetDateTime( &tempPtr->theLastModCheck );
  130.     tempPtr->next = NULL;
  131.     
  132.     AddToList( (ItemPtr *)&gWatchVolumePtr, (ItemPtr)tempPtr );
  133.  
  134.     gNumberVolumes++;
  135.     
  136.     return true;
  137. }
  138.  
  139.  
  140. // Just set up a parameter block for a PBHGetVolParms() call.
  141.  
  142. static OSErr    GetVolInfo( short theVolRef, GetVolParmsInfoBuffer* theBuffer )
  143. {
  144.     HParamBlockRec        pb;
  145.     OSErr                err;
  146.  
  147.     pb.ioParam.ioCompletion = NULL;
  148.     pb.ioParam.ioNamePtr = NULL;
  149.     pb.ioParam.ioVRefNum = theVolRef;
  150.     pb.ioParam.ioBuffer = (Ptr)theBuffer;
  151.     pb.ioParam.ioReqCount = sizeof( *theBuffer );
  152.  
  153.     err = PBHGetVolParms( &pb, false );        // Won't do this asynchronusly
  154.     
  155.     return err;
  156. }
  157.  
  158.  
  159. // Get directory information for an FSSpec.
  160.  
  161. OSErr    GetDirInfo( FSSpec* theSpec, CInfoPBRec* thePB)
  162. {
  163.     OSErr         err;
  164.  
  165.     thePB->dirInfo.ioNamePtr = theSpec->name;
  166.     thePB->dirInfo.ioVRefNum = theSpec->vRefNum;
  167.     thePB->dirInfo.ioDrDirID = theSpec->parID;
  168.     thePB->dirInfo.ioFDirIndex = 0;    // Use ioNamePtr and ioDirID
  169.     thePB->dirInfo.ioACUser = 0;    // If this does not compile try using 
  170.                                     // thePB->dirInfo.filler2 or thePB->dirInfo.ioACUser
  171.                                     // Clear it before calling PBGetCatInfo()
  172.     err = PBGetCatInfo( thePB, false );
  173.  
  174.     return err;
  175. }
  176.  
  177.  
  178. // Just add the item to the beginning of the linked list
  179.  
  180. static void        AddToList( ItemPtr* theHeadPtr, ItemPtr theItem )
  181. {
  182.     ItemPtr        tempPtr = *theHeadPtr;
  183.     
  184.     *theHeadPtr = theItem;
  185.     theItem->next = tempPtr;
  186. }
  187.  
  188. // Just keep gWatchFolderPtr referred to in this file. 
  189.  
  190. WatchFolderPtr    GetHeadFolderPtr( void )
  191. {
  192.     return gWatchFolderPtr;
  193. }
  194.  
  195. WatchVolumePtr    GetHeadVolumePtr( void )
  196. {
  197.     return gWatchVolumePtr;
  198. }
  199.  
  200. long    GetNumberOfVolumes( void )
  201. {
  202.     return gNumberVolumes;
  203. }
  204.  
  205. long    GetNumberOfFolders( void )
  206. {
  207.     return gNumberFolders;
  208. }
  209.  
  210. void    FirstVolumeToLast( void )
  211. {
  212.     FirstToLast( (ItemPtr *)&gWatchVolumePtr );
  213. }
  214.  
  215.  
  216. // Move the first item in the watch folder list to the end of the list.
  217. // Handles an empty or one item list.
  218.  
  219. static void    FirstToLast( ItemPtr* theHeadPtr )
  220. {
  221.     ItemPtr        tempPtr = *theHeadPtr;
  222.  
  223.         // If no items in list
  224.     if ( ! tempPtr )
  225.         return;
  226.     
  227.     while ( tempPtr->next )                // Go to the last item in the linked list
  228.         tempPtr = tempPtr->next;
  229.     
  230.     if ( tempPtr != *theHeadPtr )        // Would be equal if only one folder to watch
  231.     {                                    // - then the first is the last already.
  232.         tempPtr->next = *theHeadPtr;        // Add old head of list to end
  233.         tempPtr = *theHeadPtr;                // Keep so can NULL next
  234.         *theHeadPtr = (*theHeadPtr)->next;    // Head of list is now next in list
  235.         tempPtr->next = NULL;                // Now at end of list, so next is NULL
  236.     }
  237. }
  238.  
  239.  
  240. // Given an FSSpec, get the full path to the folder specified and add it to our
  241. // 'WFol' resources. It will then be loaded by InitWatchFolders() when launched.
  242.  
  243. void    AddFolderPathResource( FSSpec* theSpec )
  244. {
  245.     Str255    aPath;
  246.     Handle    aHandle;
  247.     
  248.     if ( noErr != GetFullPath( theSpec, aPath ) )
  249.         return;
  250.         
  251.     aHandle = (Handle)NewHandle( aPath[0] + 1 );
  252.     HLock( aHandle );
  253.     BlockMoveData( aPath, *aHandle, aPath[0] + 1 );
  254.     HUnlock( aHandle );
  255.     
  256.     AddResource( aHandle, kWatchFolderResource, Unique1ID( kWatchFolderResource ), theSpec->name );
  257.     ReleaseResource( aHandle );
  258. }
  259.  
  260.  
  261. // Check through linked list to see if a folder with this volume is already
  262. // there.
  263.  
  264. static WatchVolumePtr    VolumeInList( short theVolRef )
  265. {
  266.     WatchVolumePtr    tempPtr = GetHeadVolumePtr( );
  267.     
  268.     while ( tempPtr )
  269.     {
  270.         if ( theVolRef == tempPtr->theVolRef )
  271.             break;
  272.     
  273.         tempPtr = (WatchVolumePtr)tempPtr->next;
  274.     }
  275.     
  276.     return tempPtr;
  277. }
  278.  
  279.  
  280. // Check through linked list to see if this file spec is already there.
  281.  
  282. WatchFolderPtr    FolderInList( FSSpec* theSpec )
  283. {
  284.     WatchFolderPtr    tempPtr = GetHeadFolderPtr( );
  285.  
  286.     if ( ! theSpec )
  287.         return NULL;
  288.     
  289.     while ( tempPtr )
  290.     {
  291.         if ( theSpec->vRefNum == tempPtr->theSpec.vRefNum
  292.                 && theSpec->parID == tempPtr->theSpec.parID
  293.                     && EqualString( theSpec->name, tempPtr->theSpec.name, false, false ) )
  294.         {
  295.             break;
  296.         }
  297.     
  298.         tempPtr = (WatchFolderPtr)tempPtr->next;
  299.     }
  300.     
  301.     return tempPtr;
  302. }
  303.  
  304.  
  305. // Check through linked list to see if this volume and the directory
  306. // id are of a folder being watched.
  307.  
  308. Boolean    VolumeAndDirIDInList( short theVolRef, long theDirID )
  309. {
  310.     WatchFolderPtr    tempPtr = GetHeadFolderPtr( );
  311.     Boolean            result = false;
  312.     
  313.     while ( tempPtr )
  314.     {
  315.         if ( theVolRef == tempPtr->theSpec.vRefNum
  316.                 && theDirID == tempPtr->theDirID )
  317.         {
  318.             result = true;
  319.             break;
  320.         }
  321.     
  322.         tempPtr = (WatchFolderPtr)tempPtr->next;
  323.     }
  324.     
  325.     return result;
  326. }
  327.  
  328.  
  329. // Given an FSFSpec return the full path name for it.
  330.  
  331. static OSErr    GetFullPath( FSSpec* theSpec, StringPtr thePath )
  332. {
  333.     CInfoPBRec    pb;
  334.     Str255        dirName;
  335.     OSErr        err;
  336.     
  337.     thePath[0] = 0;        // Null the string
  338.     InsertAtBeginning( theSpec->name, thePath );
  339.     InsertAtBeginning( "\p:", thePath );    // Add the folder name
  340.     
  341.     pb.dirInfo.ioNamePtr = dirName;
  342.     pb.dirInfo.ioVRefNum = theSpec->vRefNum;
  343.     pb.dirInfo.ioDrParID = theSpec->parID;
  344.     pb.dirInfo.ioFDirIndex = -1;            // Get info about the directory
  345.     
  346.     do
  347.     {
  348.         pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
  349.         err = PBGetCatInfo( &pb, false);
  350.         if ( noErr != err ) goto done;
  351.             
  352.         InsertAtBeginning( dirName, thePath );
  353.         if ( pb.dirInfo.ioDrDirID != fsRtDirID )    // If it's not the disk name
  354.             InsertAtBeginning( "\p:", thePath );    // Then add a : ready for next directory
  355.         
  356.     } while ( pb.dirInfo.ioDrDirID != fsRtDirID );
  357.  
  358. done:    
  359.     return err;
  360. }
  361.  
  362.  
  363. // Simply inserts the pascal source string at the beginning of the
  364. // destination pascal string.
  365.  
  366. static void    InsertAtBeginning( StringPtr sourceStr, StringPtr destStr )
  367. {
  368.     BlockMoveData( (void *)&destStr[1], (void *)( &destStr[1] + sourceStr[0] ), destStr[0] );
  369.     BlockMoveData( (void *)&sourceStr[1], (void *)&destStr[1], sourceStr[0] );
  370.     destStr[0] += sourceStr[0];
  371. }
  372.